from collections import Counter, defaultdict
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
import time

ENCODING = 'utf8'
def timeit(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        ret = func(*args, **kwargs)
        print(f"time: {time.time() - start:.2f}s")
        return ret

    return wrapper

def hashCountBlkparse(path: str):
    cnt = 0
    shitCnt = 0
    hashCounter = Counter()
    distance = defaultdict(int)
    distanceCounter = Counter()

    with open(path, 'r', encoding=ENCODING) as f:
        for line in f:
            elems = line.strip().split(' ')
            blk, rw, hash_line = int(elems[4]), elems[5], elems[8]

            if blk % 8 != 0:
                print(f"Shit: {path}, blk: {blk}")

            blkCnt = blk // 8
            # cnt += blkCnt
            if rw == 'W':
                for j in range(0, len(hash_line), len(hash_line) // blkCnt):
                    cnt += 1
                    h = hash_line[j:j+len(hash_line) // blkCnt]
                    hashCounter[h] += 1
                    prev = distance[h]
                    if prev != 0:
                        distanceCounter[cnt - prev] += 1
                    distance[h] = cnt
            else:
                print("Error: not W")

    assert cnt == sum(hashCounter.values())
    return list(distanceCounter.values())

def hashCountHitsztrace(path: str):
    # 获取每个哈希的出现次数
    hashCounter = Counter()
    distance = defaultdict(int)
    distanceCounter = Counter()
    cnt = 0
    with open(path, 'r', encoding=ENCODING) as f:
        for line in f:
            elems = line.strip().split(' ')
            lbn, h = int(elems[2]), elems[3]

            cnt += 1
            hashCounter[h] += 1
            prev = distance[h]
            if prev != 0:
                distanceCounter[cnt - prev] += 1
            distance[h] = cnt
    
    return list(distanceCounter.values())

def drawRefDistance():
    """哈希值的cdf图(仅输出数据, 不画图)
    """
    traceNameList = ['hitsz', 'homes', 'mail', 'web', 'Nexus-5X']
    traceList = list(map(lambda x: f"{x}_16GB.hitsztrace", traceNameList))
    for i in range(len(traceList)):
        trace = f"./16/{traceList[i]}"
        name = traceNameList[i]
        print(trace)
        values = hashCountHitsztrace(trace)

        # values: 各个距离值的频数
        with open(f"{name}.txt", 'w', encoding=ENCODING) as f:
            f.write(str(values))
        continue
        pdf = np.zeros(max(values) + 1)  # 横轴为频数(1 到 最大频数), 0号位置就放一个0
        for value in values:
            pdf[value] += 1  # 该频数占总频数的比例, 确保pdf总和为sum(values), 即总的哈希值个数

        # 计算cdf
        cdf = np.cumsum(pdf) / sum(pdf)

@timeit
def hashTestHitsztrace(path: str, preSearch: int):
    # 获取每个哈希的出现次数
    wRefCnt = 0
    buffer = []
    bufMax = 512
    cnt = 0
    with open(path, 'r', encoding=ENCODING) as f:
        for line in f:
            elems = line.strip().split(' ')
            lbn, h = int(elems[2]), elems[3]

            cnt += 1
            
            for i in range(min(len(buffer), preSearch)):
                if buffer[-i-1] == h:
                    break
            else:
                if len(buffer) >= bufMax:
                    buffer.clear()
                    wRefCnt += 1
                
                buffer.append(h)
    return wRefCnt
                    

def main():
    traceNameList = ['hitsz', 'homes', 'mail', 'web', 'Nexus-5X']
    traceList = list(map(lambda x: f"{x}_16GB.hitsztrace", traceNameList))
    for i in range(len(traceList)):
        trace = f"./16/{traceList[i]}"
        name = traceNameList[i]
        for preSearch in [0, 1, 3, 5, 512]:
            res = hashTestHitsztrace(trace, preSearch)
            print(f"{name} preSearch: {preSearch} wRefCnt: {res}")
        return

if __name__ == '__main__':
    main()
